package com.seres.aop;

import com.seres.annotation.AuthToken;
import com.seres.client.mapper.log.SysLogMapper;
import com.seres.client.model.log.SysLog;
import com.seres.oplogs.OplogService;
import com.seres.response.ApiResponse;
import com.seres.util.AnnotationUtil;
import com.seres.util.BaseController;
import com.seres.util.ValidatorTools;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Aspect
@Component
public class OpogAspect extends BaseController {

    @Resource
    private SysLogMapper logMapper;

    @Resource
    private OplogService logService;

    /*
     * @author Tan-Bowen
     * @description TODO  Spring中使用@Pointcut注解来定义方法切入点
     * @Pointcut 用来定义切点，针对方法  @Aspect 用来定义切面，针对类
     * 后面的增强均是围绕此切入点来完成的
     * 此处仅配置被我们刚才定义的注解：AuthToken修饰的方法即可
     */
    @Pointcut("@annotation(reqLog)")
    public void print(AuthToken reqLog) {
    }

    /**
     * 001
     * 此处我使用环绕增强，在方法执行之前或者执行之后均会执行。
     */
    //01
    @Around(value = "print(reqLog)", argNames = "point,reqLog")
    public Object deBefore(ProceedingJoinPoint point, AuthToken reqLog) throws Throwable {
        if (reqLog.log()) {
            long time = System.currentTimeMillis();
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            String uri = request.getRequestURI();
            request.setAttribute("times", time);
            Signature signature = point.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;
            Method method = methodSignature.getMethod();
            List<?> args = Arrays.stream(point.getArgs()).collect(Collectors.toList());
            args = args.stream().filter(e->!(e instanceof HttpServletRequest)).collect(Collectors.toList());
            ApiResponse<?> retVal = (ApiResponse<?>) point.proceed();
            time = System.currentTimeMillis() - time;
            SysLog sysLog = SysLog.builder()
                    .ip(getIpAddr(request))
                    .methodType(request.getMethod())
                    .moduleName(AnnotationUtil.getApiMode(point.getTarget().getClass()))
                    .times(time)
                    .title(AnnotationUtil.getApiPro(method))
                    .type(logService.getType(reqLog.checkToken()))
                    .url(uri)
                    .userId(logService.getUserId(reqLog.checkToken()))
                    .code(retVal.getCode())
                    .build();
            if (!ValidatorTools.isEmpty(args)) {
                sysLog.setRequestParam(args);
            }
            ValidatorTools.checkSqlSuccess(logMapper.insert(sysLog), "创建日志失败");
//            log.info("日志：{}", sysLog);
            return retVal;
        }
        return point.proceed();
    }



}
